package com.zx.viewlearn.views.mypullrorefresh;

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.RelativeLayout;

import com.zx.viewlearn.views.pullableview.Pullable;


/**
 * TODO: document your custom view class.
 */
public class PullToRefreshView extends RelativeLayout {
    StateListener mViewRefreshListener;
    StateListener mViewLoadListener;

    View refreshView;
    View contentView;
    View loadmoreView;

    boolean isFistLayout = true;
    // 下拉的距离。注意：pullDownY和pullUpY不可能同时不为0
    public float pullDownY = 0;
    // 上拉的距离
    private float pullUpY = 0;

    // 释放刷新的距离
    private float refreshDist = 200;
    // 释放加载的距离
    private float loadmoreDist = 200;
    //回滚速度
    float MOVE_SPEED = 8;
    // 在刷新过程中滑动操作
    private boolean isTouch = false;
    // 按下Y坐标，上一个事件点Y坐标
    private float downY, lastY;

    // 手指滑动距离与下拉头的滑动距离比，中间会随正切函数变化
    private float radio = 2;

    //最小滑动距离
    private int minDistance = 5;

    // 当前状态
    private int state = INIT;

    // 初始状态
    public static final int INIT = 0;
    // 释放刷新
    public static final int RELEASE_TO_REFRESH = 1;
    // 正在刷新
    public static final int REFRESHING = 2;
    // 释放加载
    public static final int RELEASE_TO_LOAD = 3;
    // 正在加载
    public static final int LOADING = 4;
    // 操作完毕
    public static final int DONE = 5;

    // 这两个变量用来控制pull的方向，如果不加控制，当情况满足可上拉又可下拉时没法下拉
    private boolean canPullDown = true;
    private boolean canPullUp = true;
    boolean childCanPullDown = true;//子控件是否可以下拉，如果可以，则当前控件不滑动
    boolean childCanPullUp = true;//子控件是否可以下拉，如果可以，则当前控件不滑动

    public PullToRefreshView(Context context) {
        super(context);

        init(context, null);
    }

    public PullToRefreshView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {

    }

    private void initView() {
        refreshView = getChildAt(1);
        if (refreshView instanceof StateListener) {//设置监听
            mViewRefreshListener = (StateListener) refreshView;
        }
        contentView = getChildAt(0);
        if (refreshView == null) {
            throw new RuntimeException("refreshView is null,please add one refreshView");
        }
        if (contentView == null) {
            throw new RuntimeException("contentView is null,please add one contentView");
        }
        loadmoreView = getChildAt(2);
        if (loadmoreView instanceof StateListener) {//设置监听
            mViewLoadListener = (StateListener) loadmoreView;
        }

        refreshDist = refreshView.getMeasuredHeight();
        loadmoreDist = loadmoreView.getMeasuredHeight();
        Log.e("PullToRefreshView", "initView" + refreshDist);
    }

    int model = 0;//展示模式

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {

        if (isFistLayout == true) {
            initView();
            isFistLayout = false;
        }
        switch (model) {
            case 0:
                model0();
                break;
            case 1:
                model1();
                break;
            default:
                break;
        }

//        Log.e("PullToRefreshView", "onLayout");
    }

    private void model0() {
        //头部view的位置显示
        refreshView.layout(0, (int) (pullDownY + pullUpY) - refreshView.getMeasuredHeight(), refreshView.getMeasuredWidth(), (int) (pullDownY + pullUpY));
        //中间view的位置显示
        contentView.layout(0, (int) (pullDownY + pullUpY), contentView.getMeasuredWidth(), (int) (pullDownY + pullUpY) + contentView.getMeasuredHeight());

        //底部view的位置显示
        loadmoreView.layout(0,
                (int) (pullDownY + pullUpY) + contentView.getMeasuredHeight(),
                contentView.getMeasuredWidth(),
                (int) (pullDownY + pullUpY) + contentView.getMeasuredHeight() + loadmoreView.getMeasuredHeight());
    }

    private void model1() {
        //头部view的位置显示
        refreshView.layout(0, (int) (pullDownY + pullUpY) - refreshView.getMeasuredHeight(), refreshView.getMeasuredWidth(), (int) (pullDownY + pullUpY));
        //中间view的位置显示
        contentView.layout(0, (int) (0 + pullUpY), contentView.getMeasuredWidth(), (int) (0 + pullUpY) + contentView.getMeasuredHeight());

        //底部view的位置显示
        loadmoreView.layout(0,
                (int) (pullDownY + pullUpY) + contentView.getMeasuredHeight(),
                contentView.getMeasuredWidth(),
                (int) (pullDownY + pullUpY) + contentView.getMeasuredHeight() + loadmoreView.getMeasuredHeight());
    }

    /**
     * 不限制上拉或下拉
     */
    private void releasePull() {
        canPullDown = true;
        canPullUp = true;
    }


    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
//        Log.e("PullToRefreshView", "dispatchTouchEvent");
        //请求所有父控件及祖宗控件不要拦截事件
        getParent().requestDisallowInterceptTouchEvent(true);
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downY = ev.getY();
                lastY = downY;
                releasePull();
                break;
            case MotionEvent.ACTION_MOVE:
//                Log.e("PullToRefreshView", "dispatchTouchEvent:ACTION_MOVE" + pullDownY);
                if (contentView instanceof Pullable) {
                    childCanPullDown = ((Pullable) contentView).canPullDown();
                    childCanPullUp = ((Pullable) contentView).canPullUp();
                }

                if (pullDownY > 0
                        || childCanPullDown && canPullDown && state != LOADING) {//下拉
                    pullDownY = pullDownY + ev.getY() - lastY;
//                    pullDownY = pullDownY + (ev.getY() - lastY) / radio - minDistance;
//                    Log.e("PullToRefreshView", "dispatchTouchEvent:ACTION_MOVE" + pullDownY);
                    if (pullDownY < 0) {//不能向上划
                        pullDownY = 0;
                    }
                    if (pullDownY > getMeasuredHeight())//不能超过view高度
                        pullDownY = getMeasuredHeight();
                    if (state == REFRESHING) {
                        // 正在刷新的时候触摸移动
                        isTouch = true;
                    }
//                    Log.e("PullToRefreshView", "dispatchTouchEvent:pullDownY:" + pullDownY);
                } else if (pullUpY < 0 || childCanPullUp && canPullUp && state != REFRESHING) {
                    pullUpY = pullUpY + ev.getY() - lastY;
//                    pullUpY = pullUpY + (ev.getY() - lastY) / radio + minDistance;
                    if (pullUpY > 0) {
                        pullUpY = 0;
                    }
                    if (pullUpY < -getMeasuredHeight())//不能超过view高度
                        pullUpY = -getMeasuredHeight();
                    if (state == LOADING) {
                        // 正在加载的时候触摸移动
                        isTouch = true;
                    }
//                    Log.e("PullToRefreshView", "dispatchTouchEvent:pullUpY:" + pullUpY);
                } else {
                    releasePull();

                }

                lastY = ev.getY();

                // 根据下拉距离改变比例
                radio = (float) (2 + 2 * Math.tan(Math.PI / 2 / getMeasuredHeight()
                        * (pullDownY + Math.abs(pullUpY))));
                if (pullDownY > 0 || pullUpY < 0)
                    requestLayout();//重新布局

                if (pullDownY > 0) {
                    if (pullDownY <= refreshDist
                            && (state == RELEASE_TO_REFRESH || state == DONE)) {
                        // 如果下拉距离没达到刷新的距离且当前状态是释放刷新，改变状态为下拉刷新
                        changeState(INIT);
                    }
                    if (pullDownY >= refreshDist && state == INIT) {
                        // 如果下拉距离达到刷新的距离且当前状态是初始状态刷新，改变状态为释放刷新
//                        Log.e("PullToRefreshView", "dispatchTouchEvent:changeState:" + state);
                        changeState(RELEASE_TO_REFRESH);
                    }
                } else if (pullUpY < 0) {
                    // 下面是判断上拉加载的，同上，注意pullUpY是负值
                    if (-pullUpY <= loadmoreDist
                            && (state == RELEASE_TO_LOAD || state == DONE)) {
                        changeState(INIT);
                    }
                    // 上拉操作
                    if (-pullUpY >= loadmoreDist && state == INIT) {
                        changeState(RELEASE_TO_LOAD);
                    }

                }
                // 因为刷新和加载操作不能同时进行，所以pullDownY和pullUpY不会同时不为0，因此这里用(pullDownY +
                // Math.abs(pullUpY))就可以不对当前状态作区分了
                if ((pullDownY + Math.abs(pullUpY)) > 8) {
                    // 防止下拉过程中误触发长按事件和点击事件
                    ev.setAction(MotionEvent.ACTION_CANCEL);
                }
                break;
            case MotionEvent.ACTION_UP:
                if (pullDownY > refreshDist || -pullUpY > loadmoreDist)
                // 正在刷新时往下拉（正在加载时往上拉），释放后下拉头（上拉头）不隐藏
                {
                    isTouch = false;
                }
//                Log.e("PullToRefreshView", "dispatchTouchEvent:ACTION_UP:" + state);

                if (state == RELEASE_TO_REFRESH) {
                    changeState(REFRESHING);
                    // 刷新操作
//                    if (mListener != null)
//                        mListener.onRefresh(this);
                } else if (state == RELEASE_TO_LOAD) {
                    changeState(LOADING);
                    // 加载操作
//                    if (mListener != null)
//                        mListener.onLoadMore(this);
                }

//回弹
                hide();

                break;
            default:
                break;
        }
        super.dispatchTouchEvent(ev);
        return true;
    }

    private void hide() {
        myHandler.obtainMessage().sendToTarget();

    }


    Handler myHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {

            if (!isTouch) {
                // 正在刷新，且没有往上推的话则悬停，显示"正在刷新..."
                if (state == REFRESHING && pullDownY <= refreshDist) {
                    pullDownY = refreshDist;
                    requestLayout();
                    //模拟刷新成功
                    myHandler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            refreshFinish(SUCCEED);

                        }
                    }, 1000);
                    return;
                } else if (state == LOADING && -pullUpY <= loadmoreDist) {

                    pullUpY = -loadmoreDist;
                    requestLayout();
                    //模拟刷新成功
                    myHandler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            loadmoreFinish(SUCCEED);

                        }
                    }, 1000);
                    return;
                }

            }

            // 回弹速度随下拉距离moveDeltaY增大而增大
            MOVE_SPEED = (float) (8 + 55 * Math.tan(Math.PI / 2
                    / getMeasuredHeight() * (pullDownY + Math.abs(pullUpY))));
//            Log.e("PullToRefreshView", "myHandler:MOVE_SPEED" + MOVE_SPEED);
            if (pullDownY <= 0) {
                // 已完成回弹
                pullDownY = 0;
            }
            if (pullUpY >= 0) {
                // 已完成回弹
                pullUpY = 0;
            }
            if (pullDownY > 0) {
                pullDownY -= MOVE_SPEED;

            } else if (pullUpY < 0) {
                pullUpY += MOVE_SPEED;
            }
//            Log.e("PullToRefreshView", "myHandler:ACTION_UP" + pullDownY);
            requestLayout();
            //是否需要再次请求
            if (pullDownY > 0 || pullUpY < 0) {
                myHandler.obtainMessage().sendToTarget();

            }


        }
    };

    private void changeState(int state) {
        this.state = state;
        switch (state) {
            case INIT:
                //下拉刷新状态
                if (mViewRefreshListener != null)
                    mViewRefreshListener.init();
                if (mViewLoadListener != null)
                    mViewLoadListener.init();
                break;
            case RELEASE_TO_REFRESH:
                //释放后刷新
                if (mViewRefreshListener != null)
                    mViewRefreshListener.releaseToDo();
                break;
            case RELEASE_TO_LOAD:
                //释放加载
                if (mViewLoadListener != null)
                    mViewLoadListener.releaseToDo();
                break;
            case REFRESHING:
                //正在刷新
                if (mViewRefreshListener != null)
                    mViewRefreshListener.doing();
                break;
            case LOADING:
                // 正在加载状态
                if (mViewLoadListener != null)
                    mViewLoadListener.doing();
                break;
            case DONE:
                if (mViewRefreshListener != null)
                    mViewRefreshListener.done();
                if (mViewLoadListener != null)
                    mViewLoadListener.done();
                break;
            default:
                break;
        }

    }

    // 刷新成功
    public static final int SUCCEED = 0;
    // 刷新失败
    public static final int FAIL = 1;
    //刷新无数据
    public static final int NULL = 2;
    /**
     * 完成刷新操作，显示刷新结果。注意：刷新完成后一定要调用这个方法
     */
    /**
     * @param refreshResult PullToRefreshLayout.SUCCEED代表成功，PullToRefreshLayout.FAIL代表失败
     */
    public void refreshFinish(int refreshResult) {

//        switch (refreshResult) {
//            case SUCCEED:
////                    // 刷新成功
//                break;
//            case NULL:
//            case FAIL:
//            default:
//                // 刷新失败
//                break;
//        }
//
        changeState(DONE);
        if (pullDownY > 0) {
            // 刷新结果停留1秒
            new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    hide();
                }
            }.sendEmptyMessageDelayed(0, 1000);
        } else {
            hide();
        }
    }


    /**
     * 加载完毕，显示加载结果。注意：加载完成后一定要调用这个方法
     *
     * @param refreshResult PullToRefreshLayout.SUCCEED代表成功，PullToRefreshLayout.FAIL代表失败
     */
    public void loadmoreFinish(int refreshResult) {
        switch (refreshResult) {
            case SUCCEED:
                // 加载成功
                break;
            case NULL:
                //已无刷新数据
                break;
            case FAIL:
            default:
                // 加载失败
                break;
        }
        changeState(DONE);
        if (pullUpY < 0) {
            // 刷新结果停留1秒
            new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    hide();
                }
            }.sendEmptyMessageDelayed(0, 1000);
        } else {
            hide();
        }
    }
}
